﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;

namespace DevOnServer
{
    public class CAuthServer
    {
        public bool init(CNetwork network, CDatabase database)
        {
            m_database = database;

            Hashtable section = (Hashtable)ConfigurationManager.GetSection("Auth");

            m_acceptor = network.createAcceptor(Convert.ToInt32(section["port"]));
            m_neuzVersion = (string)section["neuzVersion"];

            if (m_acceptor == null)
            {
                CConsole.WriteLine("AuthServer port {0} can't be used !", section["port"]);
                return false;
            }

            section = (Hashtable)ConfigurationManager.GetSection("Char");
            m_serverList.ServerIP = (string)section["ip"];
            m_serverList.ServerName = (string)section["serverName"];

            section = (Hashtable)ConfigurationManager.GetSection("Channel");
            m_serverList.ChannelIP = (string)section["ip"];
            m_serverList.ChannelName = (string)section["channelName"];

            return true;
        }

        public bool run()
        {
            while (m_acceptor.NewClients.Count > 0)
            {
                CAuthPlayer player = _createPlayer(m_acceptor.NewClients.Dequeue());
                player.Client.send(CPacketCreator.greeting(player.ID));
            }

            for (int i = m_players.Count - 1; i >= 0; i--)
            {
                if (!m_players[i].Client.Connected)
                {
                    if (m_players[i].Account != null)
                        m_players[i].Account.Connected = false;

                    m_players[i].Client.Free = true;
                    m_players.RemoveAt(i);
                }
                else if (m_players[i].Client.Incomming.Lenght > 0)
                {
                    while (_handlePacket(m_players[i])) ;

                    m_players[i].Client.Incomming.clear();
                }
            }

            return true;
        }

        private bool _handlePacket(CAuthPlayer player)
        {
            CPacket packet = player.Client.Incomming;

            if (packet.readByte() != 0x5e)
                return false;

            packet.move(4);
            if (packet.readInt() > packet.Lenght - 13)
                return false;

            packet.move(4);
            if (packet.readInt() == 0xfc)
                _cmdHandler_Auth(player);

            return false;
        }

        private void _cmdHandler_Auth(CAuthPlayer player)
        {
            CPacket packet = player.Client.Incomming;

            string neuzVersion = packet.readString();
            string username = packet.readString();
            string password = packet.readString();

            if (neuzVersion != m_neuzVersion)
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.OldClient));
                return;
            }

            CAccount account = m_database.getAccount(username);

            if (account == null)
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.WrongUsername));
            }
            else if (account.Password != password)
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.WrongPassword));
            }
            else if (account.AccessLevel == 0 || account.BanTime >= CTime.seconds())
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.Banned));
            }
            else if (account.Connected)
            {
                player.Client.send(CPacketCreator.error(CPacketCreator.LoginError.AlreadyConnected));
            }
            else
            {
                account.Connected = true;
                player.Account = account;
                player.Client.send(CPacketCreator.serverList(username, m_serverList));
            }
        }

        private CAuthPlayer _createPlayer(CNetClient client)
        {
            CAuthPlayer player = new CAuthPlayer();

            m_nextPlayerId++;

            player.ID = m_nextPlayerId;
            player.Client = client;

            m_players.Add(player);
            return player;
        }

        private CNetAcceptor m_acceptor;

        private List<CAuthPlayer> m_players = new List<CAuthPlayer>();

        private string m_neuzVersion;

        private int m_nextPlayerId;

        private CDatabase m_database;

        private CServerList m_serverList = new CServerList();
    }
}